home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / rip.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  18KB  |  699 lines

  1. /* This file contains code to implement the Routing Information Protocol (RIP)
  2.  * and is derived from 4.2BSD code. Mike Karels of Berkeley has stated on
  3.  * TCP-IP that the code may be freely used as long as UC Berkeley is
  4.  * credited. (Well, here's some credit :-). AGB 4-28-88
  5.  
  6.  * Further documentation on the RIP protocol is now available in Charles
  7.  * Hedrick's draft RFC, as yet unnumbered. AGB 5-6-88
  8.  *
  9.  * The RIP RFC has now been issued as RFC1058. AGB 7-23-88
  10.  *
  11.  * Code gutted and substantially rewritten. KA9Q 9/89
  12.  *
  13.  * 29.08.94 DFN - pullentry moved to ripdump.c (usefull if RIP is not genned
  14.  */
  15.  
  16. /****************************************************************************
  17. *    $Id: rip.c 1.2 93/07/16 11:49:37 ROOT_DOS Exp $
  18. *    17 May 93    1.2        GT    Fix warnings.                                    *
  19. ****************************************************************************/
  20.  
  21. #include "global.h"
  22. #include "mbuf.h"
  23. #include "netuser.h"
  24. #include "udp.h"
  25. #include "timer.h"
  26. #include "iface.h"
  27. #include "ip.h"
  28. #include "internet.h"
  29. #include "rip.h"
  30. #include "arp.h"
  31.  
  32. struct rip_stat Rip_stat;
  33. int16 Rip_trace;
  34. int Rip_merge;
  35. struct rip_list *Rip_list;
  36. struct udp_cb *Rip_cb;
  37.  
  38. struct rip_refuse *Rip_refuse;
  39.  
  40. static void rip_rx __ARGS((struct iface *iface,struct udp_cb *sock,int cnt));
  41. static void proc_rip __ARGS((struct iface *iface,int32 gateway,
  42.     struct rip_route *ep,int32 ttl));
  43. static char *putheader __ARGS((char *cp,char command,char version));
  44. static char *putentry __ARGS((char *cp,int16 fam,int32 target,int32 metric));
  45. static void rip_shout __ARGS((void *p));
  46. static void send_routes __ARGS((int32 dest,int16 port,int split,int trig,
  47.     int us));
  48.  
  49. /* Send RIP CMD_RESPONSE packet(s) to the specified rip_list entry */
  50. static void
  51. rip_shout(p)
  52. void *p;
  53. {
  54.     register struct rip_list *rl;
  55.  
  56.     rl = (struct rip_list *)p;
  57.     stop_timer(&rl->rip_time);
  58.     send_routes(rl->dest,RIP_PORT,rl->flags&RIP_SPLIT,0,rl->flags&RIP_US);
  59.     set_timer(&rl->rip_time,rl->interval*1000L);
  60.     start_timer(&rl->rip_time);
  61. }
  62.  
  63. /* Send the routing table. */
  64. static void send_routes(
  65.     int32 dest,        /* IP destination address to send to */
  66.     int16 port,
  67.     int split,        /* Do split horizon? */
  68.     int trig,        /* Send only triggered updates? */
  69.     int us )            /* Include our address in update */
  70. {
  71.     char *cp;
  72.     int i,bits,numroutes,maxroutes;
  73.     int16 pktsize;
  74.     struct mbuf *bp;
  75.     struct route *rp;
  76.     struct socket lsock,fsock;
  77.     struct iface *iface;
  78.  
  79.     if((rp = rt_lookup(dest)) == NULLROUTE)
  80.         return;    /* No route exists, can't do it */
  81.     iface = rp->iface;
  82.  
  83.     /* Compute maximum packet size and number of routes we can send */
  84.     pktsize = ip_mtu(dest) - IPLEN;
  85.     pktsize = min(pktsize,MAXRIPPACKET);
  86.     maxroutes = (pktsize - RIPHEADER) / RIPROUTE;
  87.  
  88.     lsock.address = INADDR_ANY;
  89.     lsock.port = RIP_PORT;
  90.     fsock.address = dest;
  91.     fsock.port = port;
  92.  
  93.     /* Allocate space for a full size RIP packet and generate header */
  94.     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  95.         return; 
  96.     numroutes = 0;
  97.     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  98.  
  99.     /* Emit route to ourselves, if requested */
  100.     if(us){
  101.         cp = putentry(cp,RIP_IPFAM,iface->addr,0);
  102.         numroutes++;
  103.     }
  104.     /* Emit default route, if appropriate */
  105.     if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)
  106.      && (!trig || (R_default.flags & RTTRIG))){
  107.         if(!split || iface != R_default.iface){
  108.              cp = putentry(cp,RIP_IPFAM,0,R_default.metric);
  109.             numroutes++;
  110.         } else if(trig){
  111.             cp = putentry(cp,RIP_IPFAM,0,RIP_INFINITY);
  112.             numroutes++;
  113.         }
  114.     }
  115.     for(bits=0;bits<32;bits++){
  116.         for(i=0;i<HASHMOD;i++){
  117.             for(rp = Routes[bits][i];rp != NULLROUTE;rp=rp->next){
  118.                 if((rp->flags & RTPRIVATE)
  119.                  || (trig && !(rp->flags & RTTRIG))) 
  120.                     continue;
  121.  
  122.                 if(numroutes >= maxroutes){
  123.                     /* Packet full, flush and make another */
  124.                     bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  125.                     send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  126.                     Rip_stat.output++;
  127.                     if((bp = alloc_mbuf(pktsize)) == NULLBUF)
  128.                         return; 
  129.                     numroutes = 0;
  130.                     cp = putheader(bp->data,RIPCMD_RESPONSE,RIPVERSION);
  131.                 }
  132.                 if(!split || iface != rp->iface){
  133.                      cp = putentry(cp,RIP_IPFAM,rp->target,rp->metric);
  134.                     numroutes++;
  135.                 } else if(trig){
  136.                      cp = putentry(cp,RIP_IPFAM,rp->target,RIP_INFINITY);
  137.                     numroutes++;
  138.                 }
  139.             }
  140.         }
  141.     }
  142.     if(numroutes != 0){
  143.         bp->cnt = RIPHEADER + numroutes * RIPROUTE;
  144.         send_udp(&lsock,&fsock,0,0,bp,bp->cnt,0,0);
  145.         Rip_stat.output++;
  146.     } else {
  147.         free_p(bp);
  148.     }
  149. }
  150. /* Add an entry to the rip broadcast list */
  151.  
  152. int rip_add(
  153.     int32 dest,
  154.     int32 interval,
  155.     char flags )
  156. {
  157.     register struct rip_list *rl;
  158.     struct route *rp;
  159.  
  160.     if((rp = rt_lookup(dest)) == NULLROUTE){
  161.         tprintf("%s is unreachable\n",inet_ntoa(dest));
  162.         return 1;
  163.     }
  164.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  165.         if(rl->dest == dest)
  166.             break;
  167.  
  168.     if(rl == NULLRL){
  169.         /* get a chunk of memory for the rip interface descriptor */
  170.         rl = (struct rip_list *)callocw(1,sizeof(struct rip_list));
  171.  
  172.         /* tack this record on as the first in the list */
  173.         rl->next = Rip_list;
  174.         if(rl->next != NULLRL)
  175.             rl->next->prev = rl;
  176.         Rip_list = rl;
  177.         rl->dest = dest;
  178.     }
  179.     /* and the interface ptr, tick interval and flags */
  180.     rl->iface = rp->iface;
  181.     rl->interval = interval;
  182.     rl->flags = flags;
  183.  
  184.     /* set up the timer stuff */
  185.     rl->rip_time.func = rip_shout;
  186.     rl->rip_time.arg = rl;
  187.     /* This will initialize the timer and do an immediate broadcast */
  188.     rip_shout(rl);
  189.     return 0;
  190. }
  191.  
  192. /* add a gateway to the rip_refuse list which allows us to ignore their
  193.  * advertisements
  194. */
  195. int
  196. riprefadd(gateway)
  197. int32 gateway;
  198. {
  199.     register struct rip_refuse *rl;
  200.  
  201.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  202.         if(rl->target == gateway)
  203.             return 0;    /* Already in table */
  204.   
  205.  
  206.     /* get a chunk of memory for the rip interface descriptor */
  207.     rl = (struct rip_refuse *)callocw(1,sizeof(struct rip_refuse));
  208.  
  209.     /* tack this record on as the first in the list */
  210.     rl->next = Rip_refuse;
  211.     if(rl->next != NULLREF)
  212.         rl->next->prev = rl;
  213.     Rip_refuse = rl;
  214.  
  215.     /* fill in the gateway to ignore */
  216.     rl->target = gateway;
  217.     return 0;
  218. }
  219.  
  220. /* drop a RIP target */
  221. int
  222. rip_drop(dest)
  223. int32    dest;
  224. {
  225.     register struct rip_list *rl;
  226.  
  227.     for(rl = Rip_list; rl != NULLRL; rl = rl->next)
  228.         if(rl->dest == dest)
  229.             break;
  230.  
  231.     /* leave if we didn't find it */
  232.     if(rl == NULLRL)
  233.         return 0;
  234.  
  235.     /* stop the timer */
  236.     stop_timer(&rl->rip_time);
  237.  
  238.     /* Unlink from list */
  239.     if(rl->next != NULLRL)
  240.         rl->next->prev = rl->prev;
  241.     if(rl->prev != NULLRL)
  242.         rl->prev->next = rl->next;
  243.     else
  244.         Rip_list = rl->next;
  245.  
  246.     /* and deallocate the descriptor memory */
  247.     free((char *)rl);
  248.     return 0;
  249. }
  250.  
  251. /* drop a RIP-refuse target from the rip_refuse list */
  252. int
  253. riprefdrop(gateway)
  254. int32 gateway;
  255. {
  256.     register struct rip_refuse *rl;
  257.     
  258.     for(rl = Rip_refuse; rl != NULLREF; rl = rl->next)
  259.         if(rl->target == gateway)
  260.             break;
  261.   
  262.     /* leave if we didn't find it */
  263.     if(rl == NULLREF)
  264.         return 0;
  265.  
  266.     /* Unlink from list */
  267.     if(rl->next != NULLREF)
  268.         rl->next->prev = rl->prev;
  269.     if(rl->prev != NULLREF)
  270.         rl->prev->next = rl->next;
  271.     else
  272.         Rip_refuse = rl->next;
  273.  
  274.     /* and deallocate the structure memory */
  275.     free((char *)rl);
  276.     return 0;
  277. }
  278.  
  279. /* function to output a RIP CMD_RESPONSE packet for the rip_trigger list */
  280. void
  281. rip_trigger()
  282. {
  283.     register struct rip_list *rl;
  284.     int bits,i;
  285.     struct route *rp;
  286.  
  287.     for(rl=Rip_list;rl != NULLRL;rl = rl->next){
  288.         send_routes(rl->dest,RIP_PORT,(rl->flags & RIP_SPLIT),1,0);
  289.     }
  290.     /* Clear the trigger list */
  291.     R_default.flags &= ~RTTRIG;
  292.     for(bits=0;bits<32;bits++){
  293.         for(i=0;i<HASHMOD;i++){
  294.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  295.                 rp->flags &= ~RTTRIG;
  296.             }
  297.         }
  298.     }
  299. }
  300.  
  301. /* Start RIP agent listening at local RIP UDP port */
  302. int
  303. rip_init()
  304. {
  305.     struct socket lsock;
  306.  
  307.     lsock.address = INADDR_ANY;
  308.     lsock.port = RIP_PORT;
  309.  
  310.     if(Rip_cb == NULLUDP)
  311.         Rip_cb = open_udp(&lsock,rip_rx);
  312.  
  313.     return 0;
  314. }
  315.  
  316. /* Process RIP input received from 'interface'. */
  317. static void
  318. rip_rx(iface,sock,cnt)
  319. struct iface *iface;
  320. struct udp_cb *sock;
  321. int cnt;
  322. {
  323.     struct mbuf *bp;
  324.     struct socket fsock;
  325.     int cmd;
  326.     register struct rip_refuse *rfl;
  327.     struct rip_route entry;
  328.     struct route *rp;
  329.     struct rip_list *rl;
  330.     int32 ttl;
  331.  
  332.     /* receive the RIP packet */
  333.     recv_udp(sock,&fsock,&bp);
  334.  
  335.     /* increment the rcvd cnt */
  336.     Rip_stat.rcvd++;
  337.  
  338.     /* check the gateway of this packet against the rip_refuse list and
  339.      * discard it if a match is found
  340.      */
  341.     for(rfl=Rip_refuse;rfl != NULLREF;rfl = rfl->next){
  342.         if(fsock.address == rfl->target){
  343.             Rip_stat.refusals++;
  344.             if(Rip_trace > 1)
  345.                 printf("RIP refused from %s\n",
  346.                  inet_ntoa(fsock.address));
  347.             free_p(bp);
  348.             return;
  349.          }
  350.     }
  351.     cmd = PULLCHAR(&bp);
  352.     /* Check the version of the frame */
  353.     if(PULLCHAR(&bp) != RIPVERSION){
  354.         free_p(bp);
  355.         Rip_stat.version++;
  356.         return;
  357.     }
  358.     switch(cmd){
  359.     case RIPCMD_RESPONSE:
  360.         if(Rip_trace > 1)
  361.             printf("RIPCMD_RESPONSE from %s \n",inet_ntoa(fsock.address));
  362.  
  363.         Rip_stat.response++;
  364.         /* See if this interface is on our broadcast list; if so,
  365.          * use its interval to calculate entry lifetimes. Otherwise,
  366.          * use default
  367.          */
  368.         ttl = RIP_TTL;
  369.         for(rl=Rip_list; rl != NULLRL; rl = rl->next){
  370.             if(rl->iface == iface){
  371.                 ttl = rl->interval * 4;
  372.                 break;
  373.             }
  374.         }
  375.         (void)pull16(&bp);    /* remove one word of padding */
  376.         while(len_p(bp) >= RIPROUTE){
  377.             pullentry(&entry,&bp);
  378.             proc_rip(iface,fsock.address,&entry,ttl);
  379.         }
  380.         /* If we can't reach the sender of this update, or if
  381.          * our existing route is not through the interface we
  382.          * got this update on, add him as a host specific entry
  383.          */
  384.         if((rp = rt_blookup(fsock.address,32)) != NULLROUTE){
  385.             /* Host-specific route already exists, refresh it */
  386.             start_timer(&rp->timer);
  387.         } else if((rp = rt_lookup(fsock.address)) == NULLROUTE
  388.          || rp->iface != iface){
  389.             entry.addr_fam = RIP_IPFAM;
  390.             entry.target = fsock.address;
  391.             entry.metric = 0; /* will get incremented to 1 */
  392.             proc_rip(iface,fsock.address,&entry,ttl);
  393.         }
  394.         if(Rip_merge)
  395.             rt_merge(Rip_trace);
  396.         rip_trigger();
  397.         break;
  398.     case RIPCMD_REQUEST:
  399.         if(Rip_trace > 1)
  400.             printf("RIPCMD_REQUEST\n");
  401.  
  402.         Rip_stat.request++;
  403.         /* For now, just send the whole table with split horizon
  404.          * enabled when the source port is RIP_PORT, and send
  405.          * the whole table with split horizon disable when another
  406.          * source port is used. This should be replaced with a more
  407.          * complete implementation that checks for non-global requests
  408.          */
  409.         if(fsock.port == RIP_PORT)
  410.             send_routes(fsock.address,fsock.port,1,0,1);
  411.         else
  412.             send_routes(fsock.address,fsock.port,0,0,1);
  413.         break;
  414.     default:
  415.         if(Rip_trace > 1)
  416.             printf("RIPCMD: Unknown Type\n");
  417.  
  418.         Rip_stat.unknown++;
  419.         break;
  420.     } /* switch */
  421.     free_p(bp);
  422. }
  423. /* Apply a set of heuristics for determining the number of significant bits
  424.  * (i.e., the address mask) in the target address. Needed since RIP doesn't
  425.  * include the address mask for each entry.
  426.  */
  427. int
  428. nbits(target)
  429. int32 target;
  430. {
  431.     int bits;
  432.  
  433.     if(target == 0)
  434.         return 0;    /* Special case: 0.0.0.0 is the default route */
  435.  
  436.     /* Check the host-part bytes of
  437.      * the address to check for byte-wide zeros
  438.      * which we'll consider to be subnet routes.
  439.      * e.g.    44.80.0.0 will be considered to be equal to 44.80/16
  440.      * whereas 44.80.1.0 will be considered to be 44.80.1/24
  441.      */
  442.     switch (hibyte(hiword(target)) >> 6) {
  443.     case 3:    /* Class C address */
  444.         /*is it a host address ? i.e. are there any 1's in the
  445.          * host part ?
  446.          */
  447.         if(target & 0xff)
  448.             bits = 32;
  449.         else
  450.             bits = 24;
  451.         break;
  452.     case 2:  /* Class B address */
  453.         if(target & 0xff)
  454.             bits = 32;
  455.         else if(target & 0xff00)
  456.             bits = 24;
  457.         else
  458.             bits = 16;
  459.         break;
  460.         case 0:      /* Class A address */
  461.         case 1:
  462.         if(target & 0xff)
  463.             bits = 32;
  464.         else if(target & 0xff00)
  465.             bits = 24;
  466.         else if(target & 0xff0000L)
  467.             bits = 16;
  468.         else
  469.             bits = 8;
  470.     }
  471.  
  472.     return bits;
  473. }
  474. /* Remove and process a RIP response entry from a packet */
  475. static void
  476. proc_rip(iface,gateway,ep,ttl)
  477. struct iface *iface;
  478. int32 gateway;
  479. register struct rip_route *ep;
  480. int32 ttl;
  481. {
  482.     unsigned int bits;
  483.     register struct route *rp;
  484.     int add = 0;    /* action flags */
  485.     int drop = 0;
  486.     int trigger = 0;
  487.  
  488.     if(ep->addr_fam != RIP_IPFAM) {
  489.         /* Skip non-IP addresses */
  490.         if(Rip_trace > 1)
  491.             printf("RIP_rx: Not an IP RIP packet !\n");
  492.         Rip_stat.addr_family++;
  493.         return;
  494.     }
  495.     /* Guess at the mask, since it's not explicit */
  496.     bits = nbits(ep->target);
  497.  
  498.     /* Don't ever add a route to myself through somebody! */
  499.     if(bits == 32 && ismyaddr(ep->target) != NULLIF){
  500.         if(Rip_trace > 1){
  501.             printf("route to self: %s %ld\n",
  502.              inet_ntoa(ep->target),ep->metric);
  503.         }
  504.         return;
  505.     }
  506.     /* Update metric to reflect link cost */
  507.     ep->metric++;
  508.     ep->metric = min(ep->metric,RIP_INFINITY);
  509.  
  510.     /* Find existing entry, if any */
  511.     rp = rt_blookup(ep->target,bits);
  512.  
  513.     /* Don't touch private routes */
  514.     if(rp != NULLROUTE && (rp->flags & RTPRIVATE))
  515.         return;
  516.  
  517.     if(rp == NULLROUTE){
  518.         if(ep->metric < RIP_INFINITY){
  519.             /* New route; add it and trigger an update */
  520.             add++;
  521.             trigger++;
  522.         }
  523.     } else if(rp->metric == RIP_INFINITY){
  524.         /* Route is in hold-down; ignore this guy */
  525.         if(Rip_trace > 0){
  526.             printf("ignored (hold-down): %s %lu\n",
  527.              inet_ntoa(ep->target),ep->metric);
  528.         }
  529.     } else if(rp->gateway == gateway && rp->iface == iface){
  530.         /* This is the gateway for the entry we already have;
  531.          * restart the timer
  532.          */
  533.         set_timer(&rp->timer,ttl*1000L);
  534.         start_timer(&rp->timer);
  535.         if(rp->metric != ep->metric){
  536.             /* Metric has changed. Update it and trigger an
  537.              * update. If route has become unavailable, start
  538.              * the hold-down timeout.
  539.              */
  540.             if(Rip_trace){
  541.                 printf("metric change: %s %lu -> %lu\n",
  542.                  inet_ntoa(ep->target),rp->metric,ep->metric);
  543.             }
  544.             if(ep->metric == RIP_INFINITY)
  545.                 rt_timeout(rp);    /* Enter hold-down timeout */
  546.             else
  547.                 rp->metric = ep->metric;
  548.             trigger++;
  549.         }
  550.     } else {
  551.         /* Entry is from a different gateway than the current route */
  552.         if(ep->metric < rp->metric){
  553.             /* Switch to a new gateway */
  554.             if(Rip_trace > 0){
  555.                 printf("metric better: %s %lu\n",
  556.                  inet_ntoa(ep->target),ep->metric);
  557.             }
  558.             drop++;
  559.             add++;
  560.             trigger++;
  561.         } else {
  562.             /* Metric is no better, stay with current route */
  563.             if(Rip_trace > 1){
  564.                 printf("metric not better: %s %lu\n",
  565.                  inet_ntoa(ep->target),ep->metric);
  566.             }
  567.         }
  568.     }
  569.     if(drop){
  570.         /* Switching to a better gateway; delete old entry */
  571.         if(Rip_trace){
  572.             printf("route drop [%s]/%u",
  573.              inet_ntoa(ep->target),bits);
  574.             if(rp != NULLROUTE)
  575.                 printf(" %s %s %lu",rp->iface->name,
  576.                  inet_ntoa(rp->gateway),rp->metric);
  577.             printf("\n");
  578.         }
  579.         rt_drop(ep->target,bits);
  580.     }
  581.     if(add){
  582.         /* Add a new entry */
  583.         if(Rip_trace > 0){
  584.             printf("route add [%s]/%u %s",inet_ntoa(ep->target),
  585.              bits,iface->name);
  586.             printf(" [%s] %u\n",inet_ntoa(gateway),
  587.              (int)ep->metric);
  588.         }
  589.         rp = rt_add(ep->target,(unsigned) bits,gateway,iface,
  590.          (int) ep->metric,ttl,0);
  591.     }
  592.     /* If the route changed, mark it for a triggered update */
  593.     if(trigger){
  594.         rp->flags |= RTTRIG;
  595.     }
  596. }
  597. /* Send a RIP request packet to the specified destination */
  598.  
  599. int ripreq(
  600.     int32 dest,
  601.     int16 replyport )
  602. {
  603.     struct mbuf *bp;
  604.     struct socket lsock,fsock;
  605.     char *cp;
  606.  
  607.     lsock.address = INADDR_ANY;
  608.     lsock.port = replyport;
  609.  
  610.     /* if we were given a valid dest addr, ask it (the routers on that net)
  611.      * for a default gateway
  612.      */
  613.     if(dest == 0)
  614.         return 0;
  615.  
  616.     fsock.address = dest;
  617.     fsock.port = RIP_PORT;
  618.  
  619.     /* Send out one RIP Request packet as a broadcast to 'dest'  */
  620.     if((bp = alloc_mbuf(RIPHEADER + RIPROUTE)) == NULLBUF)
  621.         return -1;
  622.  
  623.     cp = putheader(bp->data,RIPCMD_REQUEST,RIPVERSION);
  624.     cp = putentry(cp,0,0L,RIP_INFINITY);
  625.     bp->cnt = RIPHEADER + RIPROUTE;
  626.     send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  627.     Rip_stat.output++;
  628.     return 0;
  629. }
  630.  
  631. #if 0  /* pullentry function moved to ripdump.c  */
  632. void
  633. pullentry(ep,bpp)
  634. register struct rip_route *ep;
  635. struct mbuf **bpp;
  636. {
  637.     ep->addr_fam = pull16(bpp);
  638.     (void)pull16(bpp);
  639.     ep->target = pull32(bpp);
  640.     (void)pull32(bpp);
  641.     (void)pull32(bpp);
  642.     ep->metric = pull32(bpp);
  643. }
  644. #endif
  645.  
  646. /* Write the header of a RIP packet */
  647.  
  648. static char *putheader(
  649.     char *cp,
  650.     char command,
  651.     char version )
  652. {
  653.     *cp++ = command;
  654.     *cp++ = version;
  655.     return put16(cp,0);
  656. }
  657.  
  658. /* Write a single entry into a rip packet */
  659.  
  660. static char *putentry(
  661.     char *cp,
  662.     int16 fam,
  663.     int32 target,
  664.     int32 metric ) 
  665. {
  666.     cp = put16(cp,fam);
  667.     cp = put16(cp,0);
  668.     cp = put32(cp,target);
  669.     cp = put32(cp,0L);
  670.     cp = put32(cp,0L);
  671.     return put32(cp,metric);
  672. }
  673. /* Route timeout handler. If route has already been marked for deletion
  674.  * then delete it. Otherwise mark for deletion and restart timer.
  675.  */
  676. void
  677. rt_timeout(s)
  678. void *s;
  679. {
  680.     register struct route *rp = (struct route *)s;
  681.  
  682.     stop_timer(&rp->timer);
  683.     if(rp->metric < RIP_INFINITY){
  684.         rp->metric = RIP_INFINITY;
  685.         if(dur_timer(&rp->timer) == 0)
  686.             set_timer(&rp->timer,RIP_TTL*1000L);
  687.         /* wait 2/3 of timeout before garbage collect */
  688.         set_timer(&rp->timer,dur_timer(&rp->timer)*2/3);
  689.         rp->timer.func = (void *)rt_timeout;
  690.         rp->timer.arg = (void *)rp;
  691.         start_timer(&rp->timer);
  692.         /* Route changed; mark it for triggered update */
  693.         rp->flags |= RTTRIG;
  694.         rip_trigger();
  695.     } else {
  696.         rt_drop(rp->target,rp->bits);
  697.     }
  698. }
  699.